using System.Buffers;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using SuperSocket.ProtoBase;

namespace SuperSocketProxy;

public sealed class HttpProxyPipeFilter : IPipelineFilter<SocketProxyPacket>
{
    private const string Match =
        @"^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$";

    private static ReadOnlySpan<byte> Colon => Encoding.UTF8.GetBytes(":");
    private static ReadOnlySpan<byte> Crlf => new byte[] { (byte)'\r', (byte)'\n' };
    private static ReadOnlySpan<byte> Host => Encoding.UTF8.GetBytes("Host: ");
    private static ReadOnlySpan<byte> Authorization => Encoding.UTF8.GetBytes("Proxy-Authorization: Basic ");

    public object Context { get; set; }
    
    public IPackageDecoder<SocketProxyPacket> Decoder { get; set; }

    public IPipelineFilter<SocketProxyPacket> NextFilter { get; private set; }

    public SocketProxyPacket Filter(ref SequenceReader<byte> reader)
    {
        var host = reader.ReadMiddleSequence(Host, Crlf);

        if (host.Length == 0)
            return default;

        var authorization = reader.ReadMiddleString(Authorization, Crlf);

        if (authorization.Length == 0)
            throw new ProtocolException($"{host}：需要账号密码");

        var authorizationSequence = new ReadOnlySequence<byte>(Convert.FromBase64String(authorization));

        try
        {
            var hostReader = new SequenceReader<byte>(host);
            var authorizationReader = new SequenceReader<byte>(authorizationSequence);

            if (!hostReader.TryReadTo(out ReadOnlySequence<byte> addressSequence, Colon, advancePastDelimiter: true))
                throw new ProtocolException($"{host}：地址错误");

            var address = addressSequence.GetString(Encoding.UTF8);
            var port = hostReader.ReadString(2, Encoding.UTF8);

            if (!authorizationReader.TryReadTo(out ReadOnlySequence<byte> usernameSequence, Colon,
                    advancePastDelimiter: true))
                throw new ProtocolException($"{host}：账号或秘密格式错误");

            var username = usernameSequence.GetString(Encoding.UTF8);
            var password = authorizationReader.Sequence.Slice(usernameSequence.Length + 1)
                .GetString(Encoding.UTF8);

            var packet = new HttpHandshakePacket
            {
                Username = username,
                Password = password,
            };

            if (Regex.IsMatch(address, Match))
                packet.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(address), Convert.ToUInt16(port));
            else
                packet.RemoteEndPoint = new DnsEndPoint(address, Convert.ToUInt16(port), AddressFamily.InterNetwork);

            NextFilter = new ProxyDataPipeFilter();
            
            return packet;
        }
        finally
        {
            reader.AdvanceToEnd();
        }
    }

    public void Reset()
    {
    }
}